import { createContext, ReactNode, useContext, useEffect, useState } from "react"
let callNumber = 0 // 全局管理 call_id
let call_return_callbacks = {}
interface WebsocketProviderProps {
  children: ReactNode
}
interface WebsocketContextType {
  callPy: (objName: string, funcName: string, args: any[]) => Promise<any>
  websocket: WebSocket | null
}

const WebsocketContext = createContext<WebsocketContextType>({
  callPy: async () => Promise.reject(new Error("WebSocket not initialized")),
  websocket: null
})

const dealPythonMessage = (message: object) => {
  console.log("处理python消息: 消息内容为: " + message)
}

const objToJson = (obj: any) => {
  return JSON.stringify(obj, (k, v) => (v == undefined ? null : v))
}

const WebsocketProvider = ({ children }: WebsocketProviderProps) => {
  const [websocket, setWebsocket] = useState<WebSocket | null>(null)
  const [wsIsOpen, setWsIsOpen] = useState<boolean>(false)

  useEffect(() => {
    // 页面刷新时重新连接websocket连接
    const page = window.location.pathname.substring(1)
    const websocketAddr = `ws://localhost:9088/eel?page=${page}`
    const ws = new WebSocket(websocketAddr)
    // websocket打开
    ws.onopen = () => {
      console.log("websocket onopen")
      setWsIsOpen(true)
    }

    // websocket 接收到消息
    ws.onmessage = (e) => {
      const message = JSON.parse(e.data)
      console.log("websocket recv: ", message)
      dealPythonMessage(message)
    }

    // websocket 关闭
    ws.onclose = () => {
      console.log("websocket closed")
      setWsIsOpen(false)
    }

    setWebsocket(ws)

    return () => {
      console.log("Cleaning up websocket connection")
      ws.close()
    }
  }, []) // 空依赖数组,effect在页面加载时执行一次

  const callPy = async (
    obj_name: string,
    func_name: string,
    args: any[]
  ): Promise<any> => {
    const callId = (callNumber += 1)
    const callObject = {
      call: callId,
      obj_name: obj_name,
      func_name: func_name,
      args
    }
    if (websocket && wsIsOpen) {
      websocket.send(objToJson(callObject))
    }
    return new Promise(function (resolve) {
      call_return_callbacks[callObject.call] = resolve
    })
  }

  return (
    <WebsocketContext.Provider value={{ websocket, callPy }}>
      {children}
    </WebsocketContext.Provider>
  )
}

const useWebsocket = (): WebsocketContextType => {
  const context = useContext(WebsocketContext)
  if (!context) {
    throw new Error("useWebSocket must be used within a WebSocketProvider")
  }
  return context
}

export { useWebsocket, WebsocketProvider }
